The "echo" subpackage of murraylab_tools is designed to automate the setup of reactions (mostly TX-TL reactions) with the Echo. The EchoRun class can produce picklists for the Echo, as well as instructions for loading a source plate to go with those instructions, when appropriate.
There are currently three main modes of operations of the Echo package, distinguished mainly by their inputs:
Programmatic Setup: You can build a TX-TL reaction (or, with a bit more difficulty, a non-TX-TL reaction) programmatically, without using a setup spreadsheet. There are a couple of functions for doing this, which can be combined:
Association Spreadsheet: Takes one or more spreadsheets describing the contents of an Echo source plate, plus a simple spreadsheet describing final concentrations of the materials of those source plates in each destination. Use this for non-TX-TL experiments, or if you have a TX-TL experiment with more source materials than can be handled in a TX-TL setup spreadsheet.
A word of warning: The quick start examples will help you jump right into setting up an experiment, but they make a number of assumptions about your experiment. Some things you'll want to check before running your own:
Additionally, be aware that the TX-TL setup scripts keep track of which source plate wells they've used in a .dat file. If you run those experiments repeatedly, they'll fill up the file and eventually error out when they run out of wells on the plate.
You can read more about how the echo package works in the next section, "How it all works", or you can skip to the example usage sections below that. For more information on tweaking settings, see Tweaking Settings at the end of this notebook.
See the following notebooks for other Echo setup features:
Reusable Plate Example
: To re-use materials stored in a fixed position on a source plate.echo_dilution_series
: To make 3D (or higher-dimension) dilution series.Every project begins with an EchoRun object. This object holds (nearly) all of the information about an experiment, and is ultimately responsible for coordinating plates and materials, and for actually writing picklists and experimental protocols.
Most EchoRun objects need a SourcePlate object. This object is responsible for keeping track of which wells have been used, and for assigning new wells on the source plate to materials that you'll want to transfer. It will try to assign wells in a way that keeps the same material in a contiguous block, buffered on either side by an empty well for ease of pipetting. SourcePlate objects are also typically associated with a .dat tracking file that lists which wells have been used on the plate. That way, you can use the same source plate over many experiments without having to manually program in which wells are forbidden. The SourcePlate object will read this file to learn what it has available to it, and will automatically write back to the same file whenever the EchoRun object controlling it writes a picklist.
Materials (DNA, chemicals, water, TX-TL, etc) on a source plate are represented by EchoSourceMaterial objects. An EchoSourceMaterial has a concentration, which is always stored in nM. However, because dsDNA is usually measured in ng/uL, and dsDNA is one of the most common materials used, EchoSourceMaterials by default assume that the concentration set in their constructors is in units of ng/uL. Any EchoSourceMaterial with length
> 0 will convert that ng/uL concentration into an internal nM concentration. Only if the length of the EchoSourceMaterial is set to 0 will it use its set concentration value directly. This convention appears in several other contexts in the echo package.
An EchoSourceMaterial is always associated with a SourcePlate. The EchoSourceMaterial keeps track of how much of itself has been used, and will request that wells be allocated on the SourcePlate.
EchoRun objects can also have a MasterMix object, which defines what materials will be put into the master mix, and at what concentrations. Association lists don't currently support master mixes, and TX-TL reactions built from CSVs will always pull their master mix information from the CSV, so this is currently only useful if you're using the dilution series function(s).
To generate an Echo picklist, you will generally need to do three things:
build_picklist_from_txtl_setup_csvs
, build_dilution_series
, or build_picklist_from_association_spreadsheet
from your EchoRun object. What this entails depends on your experiment; TX-TL setup with a setup spreadsheet and association file setups are almost completely defined by external files, while 2D dilution series experiments require some definition in your script. write_picklist
from your EchoRun object. For more information, see the examples below.
The following creates an Echo picklist and experimental protocol for a variety of fluorescent protein mixes described in "inputs/TX-TL_setup_example.xlsx".
In [1]:
import murraylab_tools.echo as mt_echo
import os.path
# Relevant input and output files. Check these out for examples of input file format.
txtl_inputs = os.path.join("txtl_setup", "inputs")
txtl_outputs = os.path.join("txtl_setup", "outputs")
stock_file = os.path.join(txtl_inputs, "TX-TL_setup_example_stocks.csv") # Source materials
recipe_file = os.path.join(txtl_inputs, "TX-TL_setup_example_recipe.csv") # Experimental setup
plate_file = os.path.join(txtl_inputs, "TX-TL_setup_example_plate.dat") # Keeps track of wells used
output_name = os.path.join(txtl_outputs, "TX-TL_setup_example") # Output (both a picklist and a
# small protocol for building the
# source plate)
# Build an EchoRun object
txtl_plate = mt_echo.SourcePlate(filename = plate_file)
txtl_echo_calculator = mt_echo.EchoRun(plate = txtl_plate)
# Describe the experiment
txtl_echo_calculator.build_picklist_from_txtl_setup_csvs(stock_file, recipe_file)
# Write results
txtl_echo_calculator.write_picklist(output_name)
The build_picklist_from_txtl_setup_csvs
function is used for creating a picklist from a TX-TL setup spreadsheet (spreadsheet version 2.0 or later -- spreadsheets from before late 2016 will not work). You will need to feed it the names of two CSV files produced from the "recipe" sheet (the first sheet, containing explicit pipetting directions) and the "stocks" sheet (the second sheet, which details the concentrations of most of the materials used in the experiment). The standard workflow looks like:
build_picklist_from_txtl_setup_csvs
, passing it the names of the two CSVs you just saved.Reaction size and master mix excess ratio are read from the recipe spreadsheet. You probably should not mess with those settings
Note that you must give each reaction a plate location, i.e. "D4" or "E07". In the Excel spreadsheet, plate locations can be added in the "Layout" tab, and will be automatically propagated to the "Recipe" tab.
build_picklist_from_txtl_setup_csvs
requires that the EchoRun object have a source plate object associated with a source plate file. It will automatically assign wells to that source plate for all the materials required to run that reaction.
The following creates an Echo picklist and simple experimental protcol for a two-way dilution series of a reporter plasmid and inducer.
In [2]:
import murraylab_tools.echo as mt_echo
import os.path
# Relevant input and output files. Check these out for examples of input file format.
dilution_inputs = os.path.join("2D_dilution_series", "inputs")
dilution_outputs = os.path.join("2D_dilution_series", "outputs")
plate_file = os.path.join(dilution_inputs, "dilution_setup_example_plate.dat") # Keeps track of wells used
output_name = os.path.join(dilution_outputs, "dilution_setup_example") # Output (both a picklist and a
# small protocol for building the
# source plate)
# Build an EchoRun object
dilution_plate = mt_echo.SourcePlate(filename = plate_file)
default_master_mix = mt_echo.MasterMix(plate = dilution_plate)
dilution_echo_calculator = mt_echo.EchoRun(plate = dilution_plate, master_mix = default_master_mix)
# Set final concentrations of two materials
gfp_final_concentrations = range(0,6,1) # in nM
atc_final_concentrations = range(0,100,10) # in ng/uL
# Define reporter plasmid material
gfp_conc = 294 # Concentration in ng/uL
gfp_len = 3202 # Size of DNA in bp
gfp = mt_echo.EchoSourceMaterial('GFP Plasmid', gfp_conc, gfp_len, dilution_plate)
# Define inducer material
atc_conc = 1000 # Concentration in ng/uL (important that this matches the units of the final concentrations)
atc_len = 0 # This isn't dsDNA, so it has 0 length.
atc = mt_echo.EchoSourceMaterial("ATc", atc_conc, atc_len, dilution_plate)
# Plan out the experiment
starting_well = "D2"
dilution_echo_calculator.build_dilution_series(gfp, atc, gfp_final_concentrations,
atc_final_concentrations, starting_well)
# Write results
dilution_echo_calculator.write_picklist(output_name)
Note the warnings -- a lot of mistakes you might make will cause you to pipette 0 nL at a time, so the code will warn you if you do so. In this case, those 0 volume pipetting steps are normal -- you just added a material to 0 concentration. Similar warnings will appear if you under-fill a reaction.
The final write_picklist
command produces two files -- an Echo picklist, and a plaintext experiment file to help you load the source plate. You can find
The Echo picklist (2D_dilution_series/outputs/dilution_setup_example_EchoInput.csv; the rest of the dilution series examples output to the same folder):
The plaintext experiment file (2D_dilution_series/outputs/dilution_setup_example_experiment_overview.csv):
You can also manually add a single material to a well (add_material_to_well
) or a rectangular block of wells (add_material_to_block
) by specifying the material (an EchoSourceMaterial object), a final concentration, and a location. For example, if we set up a dilution series using the variables above...
In [3]:
# Build an EchoRun object
dilution_plate = mt_echo.SourcePlate(filename = plate_file)
# default_master_mix = mt_echo.MasterMix(plate = dilution_plate)
dilution_echo_calculator = mt_echo.EchoRun(plate = dilution_plate, master_mix = None)
# Define materials
# Note: Don't try to re-use an existing EchoSourceMaterial object if that object has been
# used already in an EchoRun object that has had its write_picklist function called,
# or you will get errors
gfp = mt_echo.EchoSourceMaterial('GFP Plasmid', gfp_conc, gfp_len, dilution_plate)
atc = mt_echo.EchoSourceMaterial("ATc", atc_conc, atc_len, dilution_plate)
# # Plan out a dilution series
# starting_well = "D2"
# dilution_echo_calculator.build_dilution_series(gfp, atc, gfp_final_concentrations,
# atc_final_concentrations, starting_well)
...then we can add, say, bananas, to a 2x2 square in the top-left corner of the reaction.
In [4]:
# Bananas at 100 nM
bananas = mt_echo.EchoSourceMaterial('Cavendish', 100, 0)
dilution_echo_calculator.add_material_to_block(bananas, 1, 'D2', 'E3')
You can also add to a single well, if you really need to.
In [5]:
old_bananas = mt_echo.EchoSourceMaterial('Gros Michel', 100, 0)
dilution_echo_calculator.add_material_to_well(old_bananas, 3, 'F5')
If you want something to be in the final reaction but want to add it to your destination plate by hand instead of having the echo pipette it (e.g., you might not want to echo the TX-TL master mix), you can set this in the add_material_to_block
or add_material_to_well
functions. If you set this flag, directions to add this material manually will be added to the experiment overview file.
In [6]:
viscous_bananas = mt_echo.EchoSourceMaterial('Viscous', 100, 0)
dilution_echo_calculator.add_material_to_well(viscous_bananas, 5, "E4", pipette_by_hand = True)
dilution_echo_calculator.write_picklist(output_name + "_banana_case")
Notice the warnings about underfilled reactions -- this is because we're only adding a little bit of stuff to the mix, and haven't added water or any other bulk solvent. You can fill up the remainder of a well with EchoRun.fill_well_with
or EchoRun.fill_all_wells_with
:
In [7]:
dilution_plate = mt_echo.SourcePlate(filename = plate_file)
dilution_echo_calculator = mt_echo.EchoRun(plate = dilution_plate, master_mix = None)
gfp = mt_echo.EchoSourceMaterial('GFP Plasmid', gfp_conc, gfp_len, dilution_plate)
atc = mt_echo.EchoSourceMaterial("ATc", atc_conc, atc_len, dilution_plate)
# Bananas at 100 nM
bananas = mt_echo.EchoSourceMaterial('Cavendish', 100, 0)
dilution_echo_calculator.add_material_to_block(bananas, 1, 'D2', 'E3')
old_bananas = mt_echo.EchoSourceMaterial('Gros Michel', 100, 0)
dilution_echo_calculator.add_material_to_well(old_bananas, 3, 'F5')
viscous_bananas = mt_echo.EchoSourceMaterial('Viscous', 100, 0)
dilution_echo_calculator.add_material_to_well(viscous_bananas, 5, "E4", pipette_by_hand = True)
# Here's where we fill with ingredients.
water = mt_echo.EchoSourceMaterial('Water', 1, 0)
saltwater = mt_echo.EchoSourceMaterial('Salt Water', 1, 0)
dilution_echo_calculator.fill_well_with('D2', water)
dilution_echo_calculator.fill_all_wells_with(saltwater)
# All reactions are filled! No warnings!
dilution_echo_calculator.write_picklist(output_name + "_fill_case")
The build_dilution_series
function of EchoRun is useful for quickly building a grid of dilutions of two materials, one on each axis. This is useful for double titrations of, for example, plasmid vs. inducer, or titration of two inputs. If you want to do anything more complex, you'll probably need to move to a TX-TL setup spreadsheet.
This function will always output reactions in solid blocks, with the upper-left-most well specified by the starting well argument of build_dilution_series
(last argument). The function will also add a negative control well one row below the last row of the dilution series block, aligned with its first column (if you don't want a negative control reaction, then call build_dilution_series
with the flag negative_control = False
). You will not get a positive control reaction -- you'll have to add that yourself, if you want it.
Note that you must manually define source materials for 2D dilution setup. An EchoSourceMaterial object has four attributes -- a name, a concentration, a length, and a plate object.
If you want to set up multiple dilutions series, you can call build_dilution_series
multiple times on the same EchoRun object. All dilution series will be put on the same plate, and source wells for materials with the same names (including the master mix and water) will be combined. Just make sure to start each dilution series in a different well!
build_dilution_series
requires that the EchoRun object have a source plate object associated with a source plate file. It will automatically assign wells to that source plate for all the materials required to run that reaction.
The following creates an Echo picklist for an automated PCR setup with three sets of primers to be applied individually to three different plasmids, as defined in a pair of CSV files (one defining the source plate, one describing what should go in the destination plates).
The source plate definition file (association_list/inputs/association_source_sheet.csv):
The destionation file (association_list/inputs/association_destination_sheet.csv):
In [8]:
import murraylab_tools.echo as mt_echo
import os.path
# Relevant input and output files. Check these out for examples of input file format.
assoc_inputs = os.path.join("association_list", "inputs")
assoc_outputs = os.path.join("association_list", "outputs")
stock_file = os.path.join(assoc_inputs, 'association_source_sheet.csv')
assoc_file = os.path.join(assoc_inputs, 'association_final_sheet.csv')
assoc_name = os.path.join(assoc_outputs, 'association_example')
# Build an EchoRun object
assoc_echo_calculator = mt_echo.EchoRun()
assoc_echo_calculator.rxn_vol = 50000 # PCR is large-volume!
# Define which column of the source file is what
name_col = 'B'
conc_col = 'C'
len_col = 'D'
well_col = 'A'
plate_col = 'E'
# Define the source plate based on the stock file.
assoc_echo_calculator.load_source_plate(stock_file, name_col, conc_col,
len_col, well_col, plate_col)
# Build a protocol, based on the association file.
assoc_echo_calculator.build_picklist_from_association_spreadsheet(assoc_file,
well_col)
# Write the picklist
assoc_echo_calculator.write_picklist(assoc_name)
The build_picklist_from_association_spreadsheet
function is used for arbitrary mappings of source plate wells to destination wells, using 1) a spreadsheet describing the contents of each source plate, and 2) a second spreadsheet describing what materials should be put in what wells, and at what concentration. You must always set up a source plate first. This should be done by calling load_source_plate
with the name of the source plate spreadsheet and information about its organization. Alternatively, you could build your own manually. That is not recommended.
The first 'source' spreadsheet (describing the source plate) is a CSV-format spreadsheet with, at minimum, columns with the following information. You can add any number of additional columns to the source plate spreadsheet, which will be ignored by this function. This is the spreadsheet read in with the load_source_plate
command.
The second 'association' spreadsheet (describing the what materials go together) is also a CSV-format spreadsheet. This spreadsheet determines what goes into the destination well. One column of the association spreadsheet determines that row's well on the destination plate. The EchoRun object will scan through every column, ignoring the well column, taking pairs of columns from left to right. There can be any number of pairs of columns; each one will cause one material to be moved from the source plate to the destination plate. The first clumn in each pair holds the name of a material. This name must exactly match one of the material names listed in the source spreadsheet, and determines where material will be taken from. The second column in each pair describes the final concentration of that material. If the material is dsDNA (has non-zero length), the units of final concentration are assumed to be nM. Otherwise, the units of final concentration are the same as the units of concentration used for that material in the source plate.
Note that unlike the other two experimental settings of EchoRun, build_picklist_from_association_spreadsheet
does not require that its EchoRun object be associated with a source plate file or SourcePlate object prior to the function being called -- a new SourcePlate object will be manufactured from the input spreadsheet when you call load_source_plate
.
In [9]:
import murraylab_tools.echo as mt_echo
import os.path
plate_file = os.path.join("tweaking", "plate_file_example.dat")
# Build an EchoRun object
example_plate = mt_echo.SourcePlate(filename = plate_file)
example_master_mix = mt_echo.MasterMix(example_plate)
example_echo_calculator = mt_echo.EchoRun(plate = example_plate, master_mix = example_master_mix)
In [10]:
example_echo_calculator.rxn_vol = 10.5 * 1e3 # Volume IN nL!!!
Make sure to run this before running build_picklist_from_association_spreadsheet
or build_dilution_series
. You almost certainly shouldn't do this at all when using build_picklist_from_txtl_setup_csvs
, because that function will automatically extract a reaction volume from the setup spreadsheet.
This is really only relevant for the 2D dilution series TX-TL setup (build_dilution_series
) -- TX-TL setup from a spreadsheet pulls the extract fraction from the spreadsheet, and the association spreadsheet method has no knowledge of TX-TL. Accordingly, the extract fraction is an optional argument in build_dilution_series
. To modify the master mix of a reaction, you'll have to set its MasterMix object, which is most safely done with the add_master_mix
function.
Changing the buffer/extract composition can be accomplished in the constructor of the new MasterMix object. Be sure to add the new MasterMix object before calling write_picklist
! Also be sure that the new MasterMix object has the same reaction volume (rxn_vol
) as the EchoRun object. Otherwise you'll get an error.
In [11]:
new_master_mix = mt_echo.MasterMix(example_plate, extract_fraction = 0.40,
rxn_vol = example_echo_calculator.rxn_vol)
example_echo_calculator.add_master_mix(new_master_mix)
example_echo_calculator.build_dilution_series(gfp, atc, gfp_final_concentrations,
atc_final_concentrations, starting_well)
You can also add arbitrary components to the master mix. For example, the following code ads the dye DFHBI-1T to every well at a final concentration of 10 µM, from a 2 mM stock:
In [12]:
new_master_mix = mt_echo.MasterMix(example_plate,
rxn_vol = example_echo_calculator.rxn_vol)
dfhbi = mt_echo.EchoSourceMaterial("DFHBI-1T", 2000, 0, example_plate)
new_master_mix.add_material(dfhbi, 10)
example_echo_calculator.add_master_mix(new_master_mix)
example_echo_calculator.build_dilution_series(gfp, atc, gfp_final_concentrations,
atc_final_concentrations, starting_well)
To change buffer/extract aliquot size:
Buffer and extract aliquot size are controlled by the MasterMix object. Like extract percentage, aliquot sizes can be changed in the MasterMix's constructor.
Note that both aliquot sizes are in units of nL, not uL.
In [13]:
new_master_mix = mt_echo.MasterMix(example_plate,
extract_per_aliquot = 50000,
buffer_per_aliquot = 70000,
rxn_vol = example_echo_calculator.rxn_vol)
example_echo_calculator.add_master_mix(new_master_mix)
example_echo_calculator.build_dilution_series(gfp, atc, gfp_final_concentrations,
atc_final_concentrations, starting_well)
# ...
# calculator_with_odd_destination.write_picklist(...)
#...
To run a (dilution series) reaction without master mix:
You can also make a dilution series without any master mix by either creating a new EchoRun object with None
for its MasterMix, or by removing the MasterMix on an existing EchoRun object with a call to remove_master_mix
.
In [14]:
dye1 = mt_echo.EchoSourceMaterial('A Dye', 100, 0, dilution_plate)
dye2 = mt_echo.EchoSourceMaterial('Another Dye', 122, 0, dilution_plate)
dye_concentrations = [x for x in range(10)]
example_echo_calculator.remove_master_mix()
example_echo_calculator.build_dilution_series(dye1, dye2, dye_concentrations,
dye_concentrations, starting_well)
Source plate types and material types are set as optional arguments in the constructor of a SourcePlate object. The type and material of a source plate are both set by a string, which can be any string that the Echo Plate Reformat software will recognize.
In [15]:
plate_type = "384PP_AQ_BP" # This is actually the default plate value
retyped_example_plate = mt_echo.SourcePlate(filename = plate_file, SPtype = plate_type)
another_example_echo_calculator = mt_echo.EchoRun(plate = retyped_example_plate)
In [16]:
plate_name = "FirstPlate"
renamed_example_plate = mt_echo.SourcePlate(filename = plate_file, SPname = plate_name)
yet_another_example_echo_calculator = mt_echo.EchoRun(plate = renamed_example_plate)
To change the destination plate type:
Destination plate types are determined and stored directly in the EchoRun object. The destination plate type can be set by the optional argument DPtype
in the constructor of an EchoRun object, or set manually any time before calling write_picklist
on that EchoRun.
In [17]:
calculator_with_odd_destination = mt_echo.EchoRun(plate = example_plate, DPtype = "some_96_well_plate")
calculator_with_odd_destination.DPtype = "Nunc_384_black_glassbottom" # Just kidding!
# ...
# calculator_with_odd_destination.write_picklist(...)
#...
To change dead volume and max volume:
You probably shouldn't do this. If you absolutely must squeeze every last bit of efficiency out of your source wells (or if you want to use a low-dead-volume plate), you can set the dead_volume
and max_volume
variables, which are static variables in the murraylab_tools.echo package. If you change them, also make sure to set the static variable usable_volume
, which defines the volume of material in a well that can actually be used by the Echo (this is normally calculated from dead_volume
and max_volume
at package import). Also, you should do this before running any experimental protocol function.
In [18]:
from murraylab_tools.echo.echo_functions import dead_volume, max_volume, usable_volume
dead_volume = 10000 # Volume in nL!
max_volume = 75000 # Volume in nL!
usable_volume = max_volume - dead_volume # Don't forget to re-calculate this!